#!/system/bin/sh

#================================================================
#   Copyright (C) 2023 Sangfor Ltd. All rights reserved.
#   
#   文件名称：common_vars.sh
#   创 建 者：宋耀
#   创建日期：2023年07月10日
#   描    述：
#
#================================================================

# Common File Paths

YUM_CONF='/etc/yum.conf'
GRUB_CFG='/boot/grub/grub.cfg'
GRUB_DIR='/etc/grub.d'
SELINUX_CFG='/etc/selinux/config'
NTP_CONF='/etc/ntp.conf'
SYSCON_NTPD='/etc/sysconfig/ntpd'
NTP_SRV='/usr/lib/systemd/system/ntpd.service'
CHRONY_CONF='/etc/chrony.conf'
CHRONY_SYSCON='/etc/sysconfig/chronyd'
LIMITS_CNF='/etc/security/limits.conf'
SYSCTL_CNF='/etc/sysctl.conf'
CENTOS_REL='/etc/centos-release'
HOSTS_ALLOW='/etc/hosts.allow'
HOSTS_DENY='/etc/hosts.deny'
CIS_CNF='/etc/modprobe.d/CIS.conf'
RSYSLOG_CNF='/etc/rsyslog.conf'
SYSLOGNG_CONF='/etc/syslog-ng/syslog-ng.conf'
AUDITD_CNF='/etc/audit/auditd.conf'
AUDIT_RULES='/etc/audit/audit.rules'
AUDIT_RULES_ORI='/etc/audit/rules.d/audit.rules'
LOGR_SYSLOG='/etc/logrotate.d/syslog'
ANACRONTAB='/etc/anacrontab'
CRONTAB='/etc/crontab'
CRON_HOURLY='/etc/cron.hourly'
CRON_DAILY='/etc/cron.daily'
CRON_WEEKLY='/etc/cron.weekly'
CRON_MONTHLY='/etc/cron.monthly'
CRON_DIR='/etc/cron.d'
AT_ALLOW='/etc/at.allow'
AT_DENY='/etc/at.deny'
CRON_ALLOW='/etc/cron.allow'
CRON_DENY='/etc/cron.deny'
SSHD_CFG='/etc/ssh/sshd_config'
SYSTEM_AUTH='/etc/pam.d/system-auth'
PWQUAL_CNF='/etc/security/pwquality.conf'
PASS_AUTH='/etc/pam.d/common-password'
PAM_SU='/etc/pam.d/su'
GROUP='/etc/group'
LOGIN_DEFS='/etc/login.defs'
PASSWD='/etc/passwd'
SHADOW='/etc/shadow'
GSHADOW='/etc/gshadow'
BASHRC='/etc/bashrc'
PROF_D='/etc/profile.d'
MOTD='/etc/motd'
ISSUE='/etc/issue'
ISSUE_NET='/etc/issue.net'
GDM_PROFILE='/etc/gdm3/greeter.dconf-defaults'
JOURNALD='/etc/systemd/journald.conf'

#1 Initial Setup 初始设置 
#所有返回值0代表合规，1代表不合规
# 检查文件系统是否已禁用
test_module_disabled() {
  local filesystem="$1"
  local test_a=$(modprobe -n -v "$filesystem" 2>&1 | grep "install /bin/true")
  local test_b=$(lsmod | grep "$filesystem")

  if [[ "$test_a" =~ "install /bin/true" ]] && [[ "$test_b" == "" ]]; then
    return 0
  else
    return 1
  fi
}

# 检查挂载点是否存在
test_mount() {
  local target="$1"
  mount | grep -q "$target" && return
}

# 检查挂载点存在nodev、noexec、nosuid属性
test_mount_option() {
  local target="${1}"
  local mnt_option="${2}"
  mount | grep "$target" | grep -q "$mnt_option" && return
}

test_system_file_perms() {
  local dirs="$(dpkg --verify)"
  [[ -z "${dirs}" ]] || return
}

test_wrld_writable_files() {
  local dirs="$(df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type f -perm -0002)"
  [[ -z "${dirs}" ]] || return
}

test_unowned_files() {
  local dirs="$(df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -nouser)"
  [[ -z "${dirs}" ]] || return
}

test_ungrouped_files() {
  local dirs="$(df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -nogroup)"
  [[ -z "${dirs}" ]] || return
}

test_suid_executables() {
  local dirs="$(df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type f -perm -4000)"
  [[ -z "${dirs}" ]] || return
}

test_sgid_executables() {
  local dirs="$(df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type f -perm -2000)"
  [[ -z "${dirs}" ]] || return
}



# 检查本地文件系统中具有可写权限但不具备 SUID 权限的目录
test_sticky() {
  local dirs=`df --local -P | awk '{ if ( NR != 1 ) print $6 }' | xargs -I '{}' find '{}' -xdev -type d \( -perm -0002 -a ! -perm -1000 \) 2>/dev/null`
  [[ -z "${dirs}" ]] || return
}

test_apt_cache(){
  apt-cache policy &>/dev/null || return
}


# 检查服务是自启
test_service_enabled(){
  local service="$1"
  systemctl is-enabled "${service}" 2>&1 | grep -q 'enabled' || return 
}


# 检查服务不是自启
test_service_disable(){
  local service="$1"
  systemctl is-enabled "${service}" 2>&1 | egrep -q 'disabled|Failed|indirect' || return
}

# 检查服务是开启状态
test_service_active(){
  local service="$1"
  systemctl is-active "${service}" 2>&1 | grep -qw 'active'  || return 
}

# 检查服务不是开启状态
test_service_failed(){
  local service="$1"
  systemctl is-failed "${service}" 2>&1 | grep -qw 'inactive' || return
}

#apt 相关
test_apt_list(){
  apt-key list &>/dev/null || return
}


# 检查apt包是已安装
test_apt_installed() {
  local apt="$1"
  [[ $(dpkg -l $apt 2>/dev/null) ]] || return 2    
 }

# 检查apt包是未安装
test_apt_uninstalled() {
  local apt="$1"
  [[ $(dpkg -l $apt 2>/dev/null) ]] || return 0 && return 1 
}
# 检查crontab规则是否存在
test_crontab() {
  [[ -n "$(grep -Ers '^([^#]+\s+)?(\/usr\/s?bin\/|^\s*)aide(\.wrapper)?\s(--?\S+\s)*(--(check|update)|\$AIDEARGS)\b' /etc/cron.* $CRONTAB /var/spool/cron/)" ]] || return
}

#检查文件权限
test_file_perms() {
  local file="${1}"
  local pattern="${2}"
  stat -L -c "%a" ${file} | grep -qE "^${pattern}$"
}
#检查文件所属主，所有组
test_root_owns() {
  local file="${1}"
  stat -L -c "%u %g" ${file} 2>/dev/null | grep -q '0 0' 
}
#
test_grub_not_overridden(){
  grep -qE '^\s*chmod\s+[0-7][0-7][0-7]\s+\$\{grub_cfg\}\.new' -A 1 -B1 /usr/sbin/grub-mkconfig || return
}

# 检查grub password
test_grub_password(){
  local test_grub_superusers=`grep "^set superusers" $GRUB_CFG`
  local test_grub_password=`grep "^password"  $GRUB_CFG`
  if [[ "$test_grub_superusers" != "" ]] && [[ "$test_grub_password" != "" ]]; then
    return 0
  else
    return 1
  fi
}

# AppArmor 相关检查
test_apparmor_enabled(){
  local appArmor=`grep "^\s*linux" $GRUB_CFG | grep -v "apparmor=1" `
  local appArmor_security=`grep "^\s*linux" $GRUB_CFG | grep -v "security=apparmor"`
  if [[ "$test_grub_superusers" == "" ]] && [[ "$test_grub_password" == "" ]]; then
    return 0
  else
    return 1
  fi
}

test_apparmor_profiles() {
  # 执行 apparmor_status 命令并保存输出
  status_output=$(apparmor_status)

  # 检查是否有进程定义了配置文件
  processes_defined=$(echo "$status_output" | grep -o '^[0-9]\+ processes have profiles defined.')
  if [ -z "$processes_defined" ]; then
    return 1
  fi

  # 根据传入的参数检查进程是否处于指定模式
  local mode=$1
  mode_count=$(echo "$status_output" | grep -o "^[0-9]\+ processes are in $mode mode.")
  if [ -z "$mode_count" ]; then
    return 1
  fi

  return 0
}

# 检查grub 文件 permissions  ownership
test_grub_permissions(){
  test_file_perms ${GRUB_CFG} 400 &&  test_root_owns ${GRUB_CFG} || return
}

# 检查在单用户模式(救援模式)下进行身份验证可以防止未经授权的用户将系统重新引导为单用户以在没有凭据的情况下获得根权限。
test_grub_auth(){
   grep -Eq '^root:\$[0-9]' $SHADOW || return
}

# 检查limit
test_restrict_core_dumps(){
egrep -q "\*{1}[[:space:]]+hard[[:space:]]+core[[:space:]]+0" "${LIMITS_CNF}" || egrep -q "\*{1}[[:space:]]+hard[[:space:]]+core[[:space:]]+0" /etc/security/limits.d/  && test_sysctl fs.suid_dumpable 0 || return
}

# 检查xd_nx此功能有助于防止对缓冲区溢出漏洞的利用
test_xd_nx_support_enabled() {
  dmesg | egrep -q "NX[[:space:]]\(Execute[[:space:]]Disable\)[[:space:]]protection:[[:space:]]active" || return
}

#检查sysctl
#它随机安排进程的关键数据区域的地址空间address space layout randomization (ASLR)
test_sysctl(){
  local flag="$1"
  local value="$2"
  sysctl "${flag}" | cut -d= -f2 | tr -d '[[:space:]]' | grep -q "${value}" || return
}

#检查selinux相关规则
test_selinux_grubcfg() {
  local grep_out1
  grep_out1="$(grep selinux=0 ${GRUB_CFG})"
  [[ -z "${grep_out1}" ]] || return
  local grep_out2
  grep_out2="$(grep enforcing=0 ${GRUB_CFG})"
  [[ -z "${grep_out2}" ]] || return
}

test_selinux_policy() {
  cut -d \# -f1 ${SELINUX_CFG} | grep 'SELINUXTYPE=' | tr -d '[[:space:]]' | grep -q 'SELINUXTYPE=targeted' || return
}

test_selinux_state_permissive() {
  local output=$(grep -Ei '^\s*SELINUX=(enforcing|permissive)' ${SELINUX_CFG})
   [[ "$output" == *"SELINUX=enforcing"* ]] || [[ "$output" == *"SELINUX=permissive"* ]] || return
}

test_selinux_state_enforcing() {
  local output=$(grep -i '^\s*SELINUX=enforcing' ${SELINUX_CFG})
  [[ "$output" == *"SELINUX=enforcing"* ]] || return
}

test_unconfined_procs() {
  local ps_out
  ps_out="$( ps -eZ | grep unconfined_service_t)"
  [[ -z ${ps_out} ]] || return
}

# 检查motd 相关安全配置
test_banner(){
  local banner
  banner=$(grep -E -i "(\\\v|\\\r|\\\m|\\\s|$(grep '^ID=' /etc/os-release | cut -d= -f2 | sed -e 's/"//g'))"  ${1} 2>/dev/null)
  [[ -z "${banner}" ]] || return
}
test_permissions_0644_root_root() {
  local file=$1
  test_root_owns ${file} || return
  test_file_perms ${file} 644 || return
}

test_permissions_0600_root_root() {
  local file=$1
  test_root_owns ${file} || return
  test_file_perms ${file} 600 || return
}

test_permissions_0700_root_root() {
  local file=$1
  test_root_owns ${file} || return
  test_file_perms ${file} 700 || return
}

test_permissions_0000_root_root() {
  local file=$1
  test_root_owns ${file} || return
  test_file_perms ${file} 0 || return
}

test_rsyslog_file_perssion() {
  egrep -q '^\$FileCreateMode[[:space:]]+0640' /etc/rsyslog.conf /etc/rsyslog.d/*.conf ||  return
}

# 检查gdm相关配置 
check_config() {
    local config_file="$1"
    local config_item="$2"
    if [ -f "$config_file" ] && egrep -qw "$config_item" "$config_file"; then
        return 0
    else
        return 1
    fi
}

test_gdm_configured() {
    check_config "${GDM_PROFILE}" 'user-db:user' &&
    check_config "${GDM_PROFILE}" 'system-db:gdm' &&
    check_config "${GDM_PROFILE}" 'file-db:/usr/share/gdm/greeter-dconf-defaults' &&
    check_config "${GDM_BANNER_MSG1}" '[org/gnome/login-screen]' &&
    check_config "${GDM_BANNER_MSG1}" 'banner-message-enable=true' &&
    check_config "${GDM_BANNER_MSG1}" 'banner-message-text='
}

# 检查gdm是否禁用
test_gdm_disabled() {
    test_apt_installed "gdm3" || return 2
    check_config "${GDM_PROFILE}" 'user-db:user' &&
    check_config "${GDM_PROFILE}" 'system-db:gdm' &&
    check_config "${GDM_PROFILE}" 'file-db:/usr/share/gdm/greeter-dconf-defaults' &&
    check_config "${GDM_BANNER_MSG0}" '[org/gnome/login-screen]' &&
    check_config "${GDM_BANNER_MSG0}" 'disable-user-list=true'
}

# :X显示管理器控制协议(XDMCP)旨在为远程显示提供对显示管理服务的身份验证访问
test_XDMCP_disabled(){
  test_apt_installed "gdm3" || return 2
  grep -Eis '^\s*Enable\s*=\s*true' /etc/gdm/custom.conf || return 1
}

# 检查apt 是否存在可更新的包1表示不合规有更新的包，0代表合规都是最新的包
test_apt_check_update() {
  apt -s upgrade &>/dev/null && false
}


test_time_sync_services_enabled() {
  test_service_enabled ntp && return
  test_service_enabled systemd-timesyncd && return
  test_service_enabled chrony && return
  return 1
}
test_timesyncd_cfg(){
  timedatectl status | grep -q "System clock synchronized: yes" || return
}

test_ntp_cfg() {

  cut -d\# -f1 ${NTP_CONF} 2>/dev/null | egrep "restrict{1}[[:space:]]+default{1}" | grep kod | grep nomodify | grep notrap | grep nopeer | grep -q noquery || return
  cut -d\# -f1 ${NTP_CONF} 2>/dev/null | egrep "restrict{1}[[:space:]]+\-6{1}[[:space:]]+default" | grep kod | grep nomodify | grep notrap | grep nopeer | grep -q noquery || return
  cut -d\# -f1 ${NTP_CONF} 2>/dev/null | egrep -q "^[[:space:]]*server" || return
  cut -d\# -f1 ${SYSCON_NTPD} 2>/dev/null | grep "OPTIONS=" | grep -q "ntp:ntp" && return
  cut -d\# -f1 ${NTP_SRV} 2>/dev/null | grep "^ExecStart" | grep -q "ntp:ntp" && return
  return 1
}

test_chrony_cfg() {
  cut -d\# -f1 ${CHRONY_CONF} 2>/dev/null | egrep -q "^[[:space:]]*server" || return
  cut -d\# -f1 ${CHRONY_SYSCON} 2>/dev/null | grep "OPTIONS=" | grep -q "\-u chrony" || sed -i '/OPTIONS=/s/""/"-u chrony"/' ${CHRONY_SYSCON} || return
}

test_nfs_services_disabled() {
  test_apt_uninstalled nfs-utils || return
  test_service_disable nfs-server || return
}

test_rpcbind_services_disabled() {
  test_apt_uninstalled rpcbind || return
  test_service_disable rpcbind || return
}

test_mta_local_only() {
   ss -lntu | grep -E ':25\s' | grep -E -v '\s(127.0.0.1|\[?::1\]?):25\s' >/dev/null || return
}

test_net_ipv4_conf_all_default() {
  local suffix=$1
  local value=$2
  test_sysctl "net.ipv4.conf.all.${suffix}" ${value} || return
  test_sysctl "net.ipv4.conf.default.${suffix}" ${value} || return
}

test_net_ipv6_conf_all_default() {
  local suffix=$1
  local value=$2
  test_sysctl "net.ipv6.conf.all.${suffix}" ${value} || return
  test_sysctl "net.ipv6.conf.default.${suffix}" ${value}  return
}

test_ipv6_disabled() {
  grep_grub="$(grep "^[[:space:]]*linux" ${GRUB_CFG} | grep -v 'ipv6.disable=1')"
  [[ -z "${grep_grub}" ]] || return
}

test_tcp_wrappers_installed() {
  test_apt_installed tcp_wrappers
  test_apt_installed tcp_wrappers-libs
}

test_hosts_deny_content() {
  cut -d\# -f1 ${HOSTS_DENY} | grep -q "ALL[[:space:]]*:[[:space:]]*ALL" || return
}

# 检查firewall相关配置

test_wireless_if_disabled() {
  # Check if nmcli command is available and any wireless devices are disabled
  if command -v nmcli >/dev/null 2>&1 ; then
      nmcli radio all | grep -Eq '\s*\S+\s+disabled\s+\S+\s+disabled\b' && return 0
  elif [ -n "$(find /sys/class/net/*/ -type d -name wireless)" ]; then
      t=0
      drivers=$(for driverdir in $(find /sys/class/net/*/ -type d -name wireless | xargs -0 dirname); do basename "$(readlink -f "$driverdir"/device/driver)";done | sort -u)
      for dm in $drivers; do
          if grep -Eq "^\s*install\s+$dm\s+/bin/(true|false)" /etc/modprobe.d/*.conf; then
              /bin/true
          else
              return 1
              t=1
          fi
      done
      [[ $t -eq 0 ]] && return 1
  else
   return 0
  fi
  
  # Check if wireless modules are disabled
  mname=$(find /sys/class/net/*/ -type d -name wireless -exec dirname {} + | xargs -I {} basename $(readlink -f {}/device/driver/module) | sort -u)
  for dm in $mname; do
    grep -Eq "^\s*install\s+$dm\s+/bin/(true|false)" /etc/modprobe.d/*.conf || return 1
  done
  
  return 0
}

#  Ensure firewalld default zone is set
test_firewalld_zone_set(){
   local zone_set=`firewall-cmd --get-default-zone 2>/dev/null`
   if [[ "$zone_set" == "zone" ]];then
     return
   else
     return 1
   fi	 
}


test_service_enabled_run(){
  local service=$1
  test_service_enabled $service && test_service_active $service || return 
}

test_firewalld_interfaces_zone(){
   local zone_set=`find /sys/class/net/* -maxdepth 1 | awk -F"/" '{print $NF}' | while read -r netint; do [ "$netint" != "lo" ] && firewall-cmd --get-active-zones 2>/dev/null| grep -B1 $netint; done`
   if [[ "$zone_set" =~ "interfaces" ]];then
     return
   else
     return 1
   fi	 
}

test_iptables_empty() {
  iptables -L -n | grep -qE '([0-9]{1,3}\.){3}[0-9]{1,3}' && return 1
  ip6tables -L -n | grep -qE '([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{1,4}' && return 1
  return 0
}

# 检查系统是否安装了nftables命令
test_cmd_check(){
  local apt=$1
  [[ "$(command -v $apt)" ]] || return 2
}

test_nftables_table() {
  test_cmd_check nft || return 2
  local table_name="$1"
  nft list tables  | grep -qE "table\s+$table_name\s+{"
  if [ $? -eq 0 ]; then
    return 0  # 表存在，返回0表示合规
  else
    return 1  # 表不存在，返回1表示不合规
  fi
}
# 检查nftables基本链是否存在，存在返回0，不存在返回1
test_nftables_base_chains() {
  test_cmd_check nft || return 2
  # 检查INPUT链是否存在
  nft list table ip filter | grep -qE 'chain input {'
  local input_chain_result=$?

  # 检查FORWARD链是否存在
  nft list table ip filter | grep -qE 'chain forward {'
  local forward_chain_result=$?

  # 检查OUTPUT链是否存在
  nft list table ip filter | grep -qE 'chain output {'
  local output_chain_result=$?

  # 检查IPv6的INPUT链是否存在
  nft list table ip6 filter | grep -qE 'chain input {'
  local ipv6_input_chain_result=$?

  # 检查IPv6的FORWARD链是否存在
  nft list table ip6 filter | grep -qE 'chain forward {'
  local ipv6_forward_chain_result=$?

  # 检查IPv6的OUTPUT链是否存在
  nft list table ip6 filter | grep -qE 'chain output {'
  local ipv6_output_chain_result=$?

  # 判断所有链是否都存在
  if [ $input_chain_result -eq 0 ] && [ $forward_chain_result -eq 0 ] && [ $output_chain_result -eq 0 ] \
     && [ $ipv6_input_chain_result -eq 0 ] && [ $ipv6_forward_chain_result -eq 0 ] && [ $ipv6_output_chain_result -eq 0 ]; then
    return 0  # 链都存在，返回0表示合规
  else
    return 1  # 链有不存在的，返回1表示不合规
  fi
}
###########ufw相关检查
# 获取当前开放的端口列表
get_open_ports() {
  # 使用ss命令获取所有监听状态的TCP端口，跳过第一行标题，然后提取端口号
  open_ports=$(ss -lntu | awk '/^tcp/ {print $5}' | cut -d ":" -f 2 | sort -u | tail -n +2)
}
test_ufw_inactive(){
  ufw status | grep -qw "inactive" || return
}

test_ufw_active(){
  ufw status | grep -qw "active" || return
}
test_ufw_run(){
  test_service_enabled ufw && test_ufw_active || return
}
test_ufw_loopback() {
  test_cmd_check ufw || return 2
  test_ufw_active || return 1

  # 检查回环接口lo的入站规则
  if ufw status | grep -qE 'Anywhere +ALLOW +IN +lo'; then
    input_loopback_rule_result=0
  else
    input_loopback_rule_result=1
  fi

  # 检查回环接口lo的出站规则
  if ufw status | grep -qE 'Anywhere +ALLOW +OUT +lo'; then
    output_loopback_rule_result=0
  else
    output_loopback_rule_result=1
  fi

  # 判断是否都存在回环流量规则
  if [ $input_loopback_rule_result -eq 0 ] && [ $output_loopback_rule_result -eq 0 ]; then
    return 0  # 都存在回环流量规则，返回0表示合规
  else
    return 1  # 存在缺失的规则，返回1表示不合规
  fi
}

# 检查是否配置了 ufw 出站连接规则
test_ufw_outbound_connections() {
  # 检查 ufw 是否已安装
  test_cmd_check ufw || return 2
  test_ufw_active || return 1

  # 检查是否已配置出站连接规则
  if ufw status | grep -q 'Anywhere (out)'; then
    # echo "合规：已配置 ufw 出站连接规则。"
    return 0
  else
    # echo "不合规：未配置 ufw 出站连接规则。"
    return 1
  fi
}

# 检查是否为所有开放端口配置了 ufw 防火墙规则
test_ufw_rules_for_open_ports() {
  # 获取当前系统上所有监听状态的TCP端口
  get_open_ports
  
  # 遍历所有开放端口，检查是否为每个端口配置了ufw规则
  for port in ${open_ports}; do
    ufw status numbered | grep "$port" | grep -q "ALLOW"
    if [ $? -ne 0 ]; then
      # echo "不合规：端口 ${port} 没有配置ufw规则。"
      return 1
    fi
  done

  # echo "合规：所有开放端口都配置了ufw防火墙规则。"
  return 0
}

# 检查是否启用了ufw的默认拒绝防火墙策略
test_ufw_default_deny_policy() {
  test_cmd_check ufw || return 2
  test_ufw_active || return 1
  # 使用ufw status verbose命令获取ufw的详细状态，并提取默认策略
  default_incoming=$(ufw status verbose | grep "Default: deny (incoming)" | wc -l)
  default_outgoing=$(ufw status verbose | grep "Default: deny (outgoing)" | wc -l)

  # 验证入站和出站的默认策略是否均为拒绝
  if [ "$default_incoming" -eq 1 ] && [ "$default_outgoing" -eq 1 ]; then
    # echo "合规：ufw的默认拒绝防火墙策略已启用。"
    return 0
  else
    # echo "不合规：ufw的默认拒绝防火墙策略未启用。"
    return 1
  fi
}


test_nftables_loopback() {
  test_cmd_check nft || return 2

  # 检查INPUT链是否存在回环接口lo的规则
  nft list table ip filter | grep -qE 'chain input \{[^}]*iifname "lo"[^}]*accept;'
  local input_loopback_rule_result=$?

  # 检查OUTPUT链是否存在回环接口lo的规则
  nft list table ip filter | grep -qE 'chain output \{[^}]*oifname "lo"[^}]*accept;'
  local output_loopback_rule_result=$?

  # 判断是否都存在回环流量规则
  if [ $input_loopback_rule_result -eq 0 ] && [ $output_loopback_rule_result -eq 0 ]; then
    return 0  # 都存在回环流量规则，返回0表示合规
  else
    return 1  # 存在缺失的规则，返回1表示不合规
  fi
}

# 检查nftables出站连接和已建立连接规则是否配置
test_nftables_outbound_established_connections() {
  test_cmd_check nft || return 2

  # 检查OUTPUT链是否存在允许出站连接的规则
  nft list table ip filter | grep -qE 'chain output \{[^}]*state new, established, related[^}]*accept;'
  local output_outbound_rule_result=$?

  # 检查INPUT链是否存在允许已建立连接的规则
  nft list table ip filter | grep -qE 'chain input \{[^}]*state established, related[^}]*accept;'
  local input_established_rule_result=$?

  # 判断是否都存在出站连接和已建立连接规则
  if [ $output_outbound_rule_result -eq 0 ] && [ $input_established_rule_result -eq 0 ]; then
    return 0  # 都存在出站连接和已建立连接规则，返回0表示合规
  else
    return 1  # 存在缺失的规则，返回1表示不合规
  fi
}

# 检查nftables是否采用默认拒绝策略
test_nftables_default_deny_policy() {
  test_cmd_check nft || return 2

  # 检查INPUT链是否采用默认拒绝策略
  nft list table ip filter | grep -qE 'chain input {[^}]*policy drop;'
  local input_policy_result=$?

  # 检查FORWARD链是否采用默认拒绝策略
  nft list table ip filter | grep -qE 'chain forward {[^}]*policy drop;'
  local forward_policy_result=$?

  # 检查OUTPUT链是否采用默认拒绝策略
  nft list table ip filter | grep -qE 'chain output {[^}]*policy drop;'
  local output_policy_result=$?

  # 判断是否都采用了默认拒绝策略
  if [ $input_policy_result -eq 0 ] && [ $forward_policy_result -eq 0 ] && [ $output_policy_result -eq 0 ]; then
    return 0  # 都采用了默认拒绝策略，返回0表示合规
  else
    return 1  # 存在未采用默认拒绝策略的链，返回1表示不合规
  fi
}
# 检查nftables规则是否是永久性的
test_nftables_persistent_rules() {
  test_cmd_check nft || return 2

  # 检查nftables规则是否使用persistent类型保存
  nft list ruleset | grep -qE '^[[:space:]]*persistent;'
  local persistent_rules_result=$?

  # 判断是否使用了persistent类型保存
  if [ $persistent_rules_result -eq 0 ]; then
    return 0  # 使用了persistent类型保存，返回0表示合规
  else
    return 1  # 没有使用persistent类型保存，返回1表示不合规
  fi
}

# 检查nftables和iptables是否共存安装
test_nftables_iptables_coexistence() {

  # 检查是否有nftables和iptables共存的情况
  test_apt_installed "nftables"
  local nftables_installed=$?

  test_apt_installed "iptables iptables-services"
  local iptables_installed=$?

  # 判断是否有共存的情况
  if [ $nftables_installed -eq 0 ] && [ $iptables_installed -eq 0 ]; then
    return 1  # 没有共存的情况，返回1表示不合规
  else
    return 0  # 有共存的情况，返回1表示合规
  fi
}

test_firewalld_masked(){
   systemctl is-enabled "${service}" 2>&1 | grep -q 'masked' || return  
}

########################## iptables相关规则######################################
# 检查iptables是否配置了回环流量
test_iptables_loopback() {
  # 检查INPUT链是否存在并且是否有允许回环流量的规则
  iptables -L INPUT -n | grep -qE '^(ACCEPT|REJECT|DROP)\s+all\s+--\s+lo\s+\*\s+0\.0\.0\.0/0\s+0\.0\.0\.0/0\s*$'
  local input_chain_configured=$?

  # 检查OUTPUT链是否存在并且是否有允许回环流量的规则
  iptables -L OUTPUT -n | grep -qE '^(ACCEPT|REJECT|DROP)\s+all\s+--\s+\*\s+lo\s+0\.0\.0\.0/0\s+0\.0\.0\.0/0\s*$'
  local output_chain_configured=$?

  # 判断是否配置了回环流量，如果两个链都配置了，则表示合规
  if [ $input_chain_configured -eq 0 ] && [ $output_chain_configured -eq 0 ]; then
    return 0  # 配置了回环流量，返回0表示合规
  else
    return 1  # 没有配置回环流量，返回1表示不合规
  fi
}


# 检查iptables是否配置了出站和已建立连接
test_iptables_outbound_and_established() {
  # 检查OUTPUT链是否存在，并且是否有允许出站流量的规则
  iptables -L OUTPUT | grep -qE '^(ACCEPT|REJECT|DROP)\s+all\s+--\s+\*\s+\*\s+0\.0\.0\.0/0\s+0\.0\.0\.0/0\s*$'
  local outbound_configured=$?

  # 检查INPUT链是否存在，并且是否有允许已建立连接的规则
  iptables -L INPUT | grep -qE '^(ACCEPT|REJECT|DROP)\s+all\s+--\s+\*\s+\*\s+0\.0\.0\.0/0\s+0\.0\.0\.0/0\s+state\s+RELATED,ESTABLISHED\s*$'
  local established_configured=$?

  # 判断是否配置了出站和已建立连接
  if [ $outbound_configured -eq 0 ] && [ $established_configured -eq 0 ]; then
    return 1  # 配置了出站和已建立连接，返回1表示合规
  else
    return 0  # 没有配置出站和已建立连接，返回0表示不合规
  fi
}

# 获取当前开放的端口列表
get_open_ports() {
  # 使用ss命令获取所有监听状态的TCP端口，跳过第一行标题，然后提取端口号
  open_ports=$(ss -lntu | awk '/^tcp/ {print $5}' | cut -d ":" -f 2 | sort -u | tail -n +2)
}

# 检查iptables是否存在所有开放端口的规则
test_iptables_rules_for_open_ports() {
  local cmd=$1
  # 首先获取当前开放的端口列表
  get_open_ports

  for port in "${open_ports[@]}"; do
    # 检查INPUT链是否存在包含开放端口规则的行
    $cmd -L INPUT -n | grep -qE "dpt:$port(\s|$)"
    local rule_exists=$?

    # 如果某个端口没有对应规则，直接返回不合规
    if [ $rule_exists -ne 0 ]; then
      return 1  # 存在未配置规则的端口，返回1表示不合规
    fi
  done

  # 如果所有端口都有对应规则，返回合规
  return 0
}

# 检查iptables是否采用默认的拒绝策略
test_iptables_default_deny_policy() {
  local cmd=$1
  # 检查 INPUT 链的默认策略是否为 DROP
  $cmd -L INPUT -n | grep -qE 'Chain INPUT .* \(policy (DROP|REJECT)\)'
  local input_chain_result=$?

  # 检查 FORWARD 链的默认策略是否为 DROP
  $cmd -L FORWARD -n | grep -qE 'Chain FORWARD .* \(policy (DROP|REJECT)\)'
  local forward_chain_result=$?

  # 检查 OUTPUT 链的默认策略是否为 DROP
  $cmd -L OUTPUT -n | grep -qE 'Chain OUTPUT .* \(policy (DROP|REJECT)\)'
  local output_chain_result=$?

  # 判断所有链的默认策略是否都设置为 DROP
  if [ $input_chain_result -eq 0 ] && [ $forward_chain_result -eq 0 ] && [ $output_chain_result -eq 0 ]; then
    return 0  # 默认策略都为 DROP，返回0表示合规
  else
    return 1  # 存在非 DROP 的默认策略，返回1表示不合规
  fi
}

# 使用 || 简写函数，检查iptables规则是否已保存
test_iptables_rules_saved() {
  cmd=$1
  [ -f /etc/sysconfig/$cmd ] || return 1
}

#########################ip6tables规则##################################
# 检查 ip6tables 是否存在规则允许 loopback 流量
test_ip6tables_loopback() {
  # 检查INPUT链是否存在并且是否有允许回环流量的规则
  ip6tables -L INPUT -n | grep -qE '^ACCEPT\s+all\s+::1\s+::1\s*$'
  local input_chain_configured=$?

  # 检查OUTPUT链是否存在并且是否有允许回环流量的规则
  ip6tables -L OUTPUT -n | grep -qE '^ACCEPT\s+all\s+::1\s+::1\s*$'
  local output_chain_configured=$?

  # 判断是否配置了回环流量，如果两个链都配置了，则表示合规
  if [ $input_chain_configured -eq 0 ] && [ $output_chain_configured -eq 0 ]; then
    return 0  # 配置了回环流量，返回0表示合规
  else
    return 1  # 没有配置回环流量，返回1表示不合规
  fi
}

# 函数：检查 ip6tables outbound 和 established connections 是否配置合规
test_ip6tables_outbound_established() {
  
  # 检查是否存在允许 OUTBOUND 的规则和允许 ESTABLISHED 的规则
  ip6tables -L OUTPUT -n | grep -qE 'ACCEPT\s+all\s+::/0\s+::/0' && \
  ip6tables -L INPUT -n | grep -qE 'ACCEPT\s+all\s+::/0\s+::/0\s+state\s+RELATED,ESTABLISHED' || return 1

  # 如果通过以上检查，则表示合规
  return 0
}



test_audit_log_storage_size() {

  cut -d\# -f1 ${AUDITD_CNF} | egrep -q "max_log_file[[:space:]]|max_log_file=" || return
}

test_dis_on_audit_log_full() {
  cut -d\# -f2 ${AUDITD_CNF} | grep 'space_left_action' | cut -d= -f2 | tr -d '[[:space:]]' | grep -q 'email' || return
  cut -d\# -f2 ${AUDITD_CNF} | grep 'action_mail_acct' | cut -d= -f2 | tr -d '[[:space:]]' | grep -q 'root' || return
  cut -d\# -f2 ${AUDITD_CNF} | grep 'admin_space_left_action' | cut -d= -f2 | tr -d '[[:space:]]' | grep -q 'halt' || return
}

test_keep_all_audit_info() {
  cut -d\# -f2 ${AUDITD_CNF} | grep 'max_log_file_action' | cut -d= -f2 | tr -d '[[:space:]]' | grep -q 'keep_logs' || return
}

test_audit_procs_prior_2_auditd() {
  grep_grub="$(grep "^[[:space:]]*linux" ${GRUB_CFG} | grep -v 'audit=1')"
  [[ -z "${grep_grub}" ]] || return
}

test_audit_backlog_limit() {
  
  grep_grub="$(grep "^\s*linux" ${GRUB_CFG} | grep -Ev 'audit_backlog_limit=\S+\b')"
  [[ -z "${grep_grub}" ]] || return
}

test_audit_date_time() {
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+time-change" | egrep "\-S[[:space:]]+settimeofday" \
  | egrep "\-S[[:space:]]+adjtimex" | egrep "\-F[[:space:]]+arch=b64" | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" ||  return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+time-change" | egrep "\-S[[:space:]]+settimeofday" \
  | egrep "\-S[[:space:]]+adjtimex" | egrep "\-F[[:space:]]+arch=b32" | egrep "\-S[[:space:]]+stime" \
 | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" || return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+time-change" | egrep "\-F[[:space:]]+arch=b64" \
  | egrep "\-S[[:space:]]+clock_settime" | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" || return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+time-change" | egrep "\-F[[:space:]]+arch=b32" \
  | egrep "\-S[[:space:]]+clock_settime" | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" || return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+time-change" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/etc\/localtime" || return
}

test_audit_user_group() {
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+identity" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/etc\/group" || return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+identity" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/etc\/passwd" || return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+identity" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/etc\/gshadow" || return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+identity" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/etc\/shadow" || return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+identity" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/etc\/security\/opasswd" || return
}

test_audit_network_env() {
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+system-locale" | egrep "\-S[[:space:]]+sethostname" \
  | egrep "\-S[[:space:]]+setdomainname" | egrep "\-F[[:space:]]+arch=b64" | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" \
 ||  return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+system-locale" | egrep "\-S[[:space:]]+sethostname" \
  | egrep "\-S[[:space:]]+setdomainname" | egrep "\-F[[:space:]]+arch=b32" | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" \
 ||  return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+system-locale" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/etc\/issue" ||  return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+system-locale" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/etc\/issue.net" ||  return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+system-locale" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/etc\/hosts" ||  return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+system-locale" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/etc\/sysconfig\/network" ||  return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+system-locale" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\w[[:space:]]+\/etc\/sysconfig\/network-scripts\/" ||  return
}

test_audit_sys_mac() {
cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+MAC-policy" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/etc\/selinux\/" ||  return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+MAC-policy" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/usr\/share\/selinux\/" ||  return
}

test_audit_logins_logouts() {
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+logins" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/var\/log\/lastlog" ||  return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+logins" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/var\/run\/faillock\/" ||  return
}

test_audit_session_init() {
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+session" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/var\/run\/utmp" || return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+logins" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/var\/log\/wtmp" ||  return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+logins" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/var\/log\/btmp" ||  return
}

test_audit_dac_perm_mod_events() {
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+perm_mod" | egrep "\-S[[:space:]]+chmod" \
  | egrep "\-S[[:space:]]+fchmod" | egrep "\-S[[:space:]]+fchmodat" | egrep "\-F[[:space:]]+arch=b64" \
  | egrep "\-F[[:space:]]+auid>=1000" | egrep "\-F[[:space:]]+auid\!=4294967295" \
  | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" \
 ||  return

  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+perm_mod" | egrep "\-S[[:space:]]+chmod" \
  | egrep "\-S[[:space:]]+fchmod" | egrep "\-S[[:space:]]+fchmodat" | egrep "\-F[[:space:]]+arch=b32" \
  | egrep "\-F[[:space:]]+auid>=1000" | egrep "\-F[[:space:]]+auid\!=4294967295" \
  | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" \
 ||  return

  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+perm_mod" | egrep "\-S[[:space:]]+chown" \
  | egrep "\-S[[:space:]]+fchown" | egrep "\-S[[:space:]]+fchownat" | egrep "\-S[[:space:]]+fchown" \
  | egrep "\-F[[:space:]]+arch=b64" | egrep "\-F[[:space:]]+auid>=1000" | egrep "\-F[[:space:]]+auid\!=4294967295" \
  | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" \
 ||  return

  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+perm_mod" | egrep "\-S[[:space:]]+chown" \
  | egrep "\-S[[:space:]]+fchown" | egrep "\-S[[:space:]]+fchownat" | egrep "\-S[[:space:]]+fchown" \
  | egrep "\-F[[:space:]]+arch=b32" | egrep "\-F[[:space:]]+auid>=1000" | egrep "\-F[[:space:]]+auid\!=4294967295" \
  | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" \
 ||  return
  
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+perm_mod" | egrep "\-S[[:space:]]+setxattr" \
  | egrep "\-S[[:space:]]+lsetxattr" | egrep "\-S[[:space:]]+fsetxattr" | egrep "\-S[[:space:]]+removexattr" \
  | egrep "\-S[[:space:]]+lremovexattr" | egrep "\-S[[:space:]]+fremovexattr" | egrep "\-F[[:space:]]+arch=b64" \
  | egrep "\-F[[:space:]]+auid>=1000" | egrep "\-F[[:space:]]+auid\!=4294967295" \
  | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" \
 ||  return

  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+perm_mod" | egrep "\-S[[:space:]]+setxattr" \
  | egrep "\-S[[:space:]]+lsetxattr" | egrep "\-S[[:space:]]+fsetxattr" | egrep "\-S[[:space:]]+removexattr" \
  | egrep "\-S[[:space:]]+lremovexattr" | egrep "\-S[[:space:]]+fremovexattr" | egrep "\-F[[:space:]]+arch=b32" \
  | egrep "\-F[[:space:]]+auid>=1000" | egrep "\-F[[:space:]]+auid\!=4294967295" \
  | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" \
 ||  return
}

test_unsuc_unauth_acc_attempts() {
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+access" | egrep "\-S[[:space:]]+creat" \
  | egrep "\-S[[:space:]]+open" | egrep "\-S[[:space:]]+openat" | egrep "\-S[[:space:]]+truncate" \
  | egrep "\-S[[:space:]]+ftruncate" | egrep "\-F[[:space:]]+arch=b64" | egrep "\-F[[:space:]]+auid>=1000" \
  | egrep "\-F[[:space:]]+auid\!=4294967295" | egrep "\-F[[:space:]]exit=\-EACCES" \
  | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" \
 ||  return

  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+access" | egrep "\-S[[:space:]]+creat" \
  | egrep "\-S[[:space:]]+open" | egrep "\-S[[:space:]]+openat" | egrep "\-S[[:space:]]+truncate" \
  | egrep "\-S[[:space:]]+ftruncate" | egrep "\-F[[:space:]]+arch=b32" | egrep "\-F[[:space:]]+auid>=1000" \
  | egrep "\-F[[:space:]]+auid\!=4294967295" | egrep "\-F[[:space:]]exit=\-EACCES" \
  | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" \
 ||  return

  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+access" | egrep "\-S[[:space:]]+creat" \
  | egrep "\-S[[:space:]]+open" | egrep "\-S[[:space:]]+openat" | egrep "\-S[[:space:]]+truncate" \
  | egrep "\-S[[:space:]]+ftruncate" | egrep "\-F[[:space:]]+arch=b64" | egrep "\-F[[:space:]]+auid>=1000" \
  | egrep "\-F[[:space:]]+auid\!=4294967295" | egrep "\-F[[:space:]]exit=\-EPERM" \
  | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" \
 ||  return

  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+access" | egrep "\-S[[:space:]]+creat" \
  | egrep "\-S[[:space:]]+open" | egrep "\-S[[:space:]]+openat" | egrep "\-S[[:space:]]+truncate" \
  | egrep "\-S[[:space:]]+ftruncate" | egrep "\-F[[:space:]]+arch=b32" | egrep "\-F[[:space:]]+auid>=1000" \
  | egrep "\-F[[:space:]]+auid\!=4294967295" | egrep "\-F[[:space:]]exit=\-EPERM" \
  | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" \
 ||  return

}

test_coll_priv_cmds() {
  local priv_cmds
  priv_cmds="$(find / -xdev \( -perm -4000 -o -perm -2000 \) -type f)"
  for cmd in ${priv_cmds} ; do
    cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+privileged" | egrep "\-F[[:space:]]+path=${cmd}" \
    | egrep "\-F[[:space:]]+perm=x" | egrep "\-F[[:space:]]+auid>=1000" | egrep "\-F[[:space:]]+auid\!=4294967295" \
    | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" || return
  done
}

test_coll_suc_fs_mnts() {
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+mounts" | egrep "\-S[[:space:]]+mount" \
  | egrep "\-F[[:space:]]+arch=b64" | egrep "\-F[[:space:]]+auid>=1000" \
  | egrep "\-F[[:space:]]+auid\!=4294967295" \
  | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" \
 ||  return

  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+mounts" | egrep "\-S[[:space:]]+mount" \
  | egrep "\-F[[:space:]]+arch=b(32|64)" | egrep "\-F[[:space:]]+auid>=1000" \
  | egrep "\-F[[:space:]]+auid\!=4294967295" \
  | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" \
 ||  return
}

test_coll_file_del_events() {
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+delete" | egrep "\-S[[:space:]]+unlink" \
  | egrep "\-F[[:space:]]+arch=b(32|64)" | egrep "\-S[[:space:]]+unlinkat" | egrep "\-S[[:space:]]+rename" \
  | egrep "\-S[[:space:]]+renameat" | egrep "\-F[[:space:]]+auid>=1000" \
  | egrep "\-F[[:space:]]+auid\!=4294967295" \
  | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" \
 ||  return

  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+delete" | egrep "\-S[[:space:]]+unlink" \
  | egrep "\-F[[:space:]]+arch=b32" | egrep "\-S[[:space:]]+unlinkat" | egrep "\-S[[:space:]]+rename" \
  | egrep "\-S[[:space:]]+renameat" | egrep "\-F[[:space:]]+auid>=1000" \
  | egrep "\-F[[:space:]]+auid\!=4294967295" \
  | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" \
 ||  return

}

test_coll_chg2_sysadm_scope() {
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+scope" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/etc\/sudoers" ||  return
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+scope" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/etc\/sudoers.d\/" ||  return

}

test_coll_sysadm_actions() {
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+actions" | egrep "\-p[[:space:]]+wa" \
  | egrep -q "\-w[[:space:]]+\/var\/log\/sudo.log" ||  return
}

test_kmod_lod_unlod() {
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+modules" | egrep "\-p[[:space:]]+x" \
  | egrep -q "\-w[[:space:]]+\/sbin\/insmod" ||  return

  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+modules" | egrep "\-p[[:space:]]+x" \
  | egrep -q "\-w[[:space:]]+\/sbin\/rmmod" ||  return

  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+modules" | egrep "\-p[[:space:]]+x" \
  | egrep -q "\-w[[:space:]]+\/sbin\/modprobe" ||  return

  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep "\-k[[:space:]]+modules" | egrep "\-S[[:space:]]+delete_module" \
  | egrep "\-F[[:space:]]+arch=b64" | egrep "\-S[[:space:]]+init_module" \
  | egrep -q "\-a[[:space:]]+always,exit|\-a[[:space:]]+exit,always" \
 ||  return
}

test_audit_cfg_immut() {
  cut -d\# -f1 ${AUDIT_RULES} ${AUDIT_RULES_ORI} | egrep -q "^-e[[:space:]]+2" ||  return
}

test_rsyslog_content() {
  grep -q "^*.*[^I][^I]*@" ${RSYSLOG_CNF} 2>/dev/null || return
}

# 函数：检查 rsyslog 是否配置了特定规则
# 返回值：0 表示合规，1 表示不合规
test_rsyslog_configured() {
  local rules=(
    "^\s*\*\.\*\s+/var/log/messages"
    "auth,authpriv\.\* /var/log/secure"
    "mail\.\* -/var/log/mail"
    "mail.info -/var/log/mail.info"
    "mail.warning -/var/log/mail.warn"
    "mail.err /var/log/mail.err"
    "news.crit -/var/log/news/news.crit"
    "news.err -/var/log/news/news.err"
    "news.notice -/var/log/news/news.notice"
    "\*\.=warning;\*\.=err -/var/log/warn"
    "\*\.crit /var/log/warn"
    "\*\.\*;mail.none;news.none -/var/log/messages"
    "local0,local1\.\* -/var/log/localmessages"
    "local2,local3\.\* -/var/log/localmessages"
    "local4,local5\.\* -/var/log/localmessages"
    "local6,local7\.\* -/var/log/localmessages"
    "kern\.\* /var/log/kern.log"
    "user\.\* /var/log/user.log"
    "cron\.\* /var/log/cron.log"
    "daemon\.\* /var/log/daemon.log"
    "syslog\.\* /var/log/syslog"
    "lpr\.\* -/var/log/lpr.log"
    "local0\.\* -/var/log/local0.log"
    "local1\.\* -/var/log/local1.log"
    "local2\.\* -/var/log/local2.log"
    "local3\.\* -/var/log/local3.log"
    "local4\.\* -/var/log/local4.log"
    "local5\.\* -/var/log/local5.log"
    "local6\.\* -/var/log/local6.log"
    "local7\.\* -/var/log/local7.log"
    "emerg\.\* /var/log/emerg.log"
    "mail.none /var/log/messages"
    "cron.none /var/log/messages"
    "authpriv.none /var/log/messages"
    "user.none /var/log/messages"
    "kern.none /var/log/messages"
    "mail.error /var/log/mailerror.log"
  )

  for rule in "${rules[@]}"; do
    grep -qE "$rule" /etc/rsyslog.conf
    if [ $? -eq 0 ]; then
      return 0  # 配置了规则，返回0表示合规
    fi
  done

  return 1  # 没有配置规则，返回1表示不合规
}


test_syslogng_content() {
  egrep -q "destination[[:space:]]+logserver[[:space:]]+\{[[:space:]]*tcp\(\".+\"[[:space:]]+port\([[:digit:]]+\)\)\;[[:space:]]*\}\;" ${SYSLOGNG_CONF} 2>/dev/null || return
  egrep -q "log[[:space:]]+\{[[:space:]]*source\(src\)\;[[:space:]]*destination\(logserver\)\;[[:space:]]*\}\;" ${SYSLOGNG_CONF} 2>/dev/null || return
}


test_rsyslog_journald() {
   journald=$1
   grep -E "$journald" ${JOURNALD} || return
}

test_rsyslog_syslogng_installed() {
  test_apt_installed rsyslog || return
  test_apt_installed syslog-ng || return
}

test_var_log_files_permissions() {
  [[ $(find /var/log -type f -ls | grep -v "\-r\-\-\-\-\-\-\-\-" | grep -v "\-rw\-\-\-\-\-\-\-" | grep -v "\-rw\-r\-\-\-\-\-" | wc -l) -eq 0 ]]  || return
}

test_logrotate_configured() {
  local logrotate_dir="/etc/logrotate.d/"

  # 检查 /etc/logrotate.d/ 目录是否存在
  if [ -d "$logrotate_dir" ]; then
    # 检查 /etc/logrotate.d/ 目录下是否有文件
    local logrotate_files=$(ls "$logrotate_dir")
    if [ -n "$logrotate_files" ]; then
      # 循环检查每个文件是否包含日志轮换规则
      for file in $logrotate_files; do
        if [ -f "$logrotate_dir$file" ]; then
          grep -qE '^\s*[^#].*rotate\s' "$logrotate_dir$file"
          if [ $? -eq 0 ]; then
            return 0  # 存在日志轮换规则，返回0表示合规
          fi
        fi
      done
    fi
  fi

  return 1  # 不存在日志轮换规则或logrotate.d目录不存在或没有文件，返回1表示不合规
}
test_logrotate_permissions(){
  grep -Es "^\s*create\s+\S+" /etc/logrotate.conf /etc/logrotate.d/* | grep -E -v -q "\s(0)?[0-6][04]0\s" && return 1
}

test_at_cron_auth_users() {
  [[ -f ${AT_DENY} ]] || touch ${AT_DENY} || return 
  [[ -f ${CRON_DENY} ]] || touch ${CRON_DENY} || return 
  [[ -f ${AT_ALLOW} ]] || touch ${AT_ALLOW} || return
  [[ -f ${CRON_ALLOW} ]] || touch ${CRON_ALLOW} || return
  test_permissions_0600_root_root "${CRON_ALLOW}" || return
  test_permissions_0600_root_root "${AT_ALLOW}" || return
}

# 函数：检查是否启用 sudo 命令使用 pty
# 返回值：0 表示合规，1 表示不合规
test_sudo_use_pty() {
  # 在 /etc/sudoers 中搜索是否存在匹配配置项
  grep -Ei '^\s*Defaults\s+([^#]\S+,\s*)?use_pty\b' /etc/sudoers > /dev/null
  local result_sudoers=$?

  # 在 /etc/sudoers.d/ 目录下搜索是否存在匹配配置项
  grep -Ei '^\s*Defaults\s+([^#]\S+,\s*)?use_pty\b' /etc/sudoers.d/* 2> /dev/null
  local result_sudoers_d=$?

  # 根据搜索结果返回合规或不合规
  [ "$result_sudoers" -eq 0 -o "$result_sudoers_d" -eq 0 ] && return 0 || return 1
}

test_sudo_log_file_configured() {
  grep -Ei '^\s*Defaults\s+([^#;]+,\s*)?logfile\s*=\s*(")?[^#;]+(")?' /etc/sudoers > /dev/null
  local result_sudoers=$?

  # 使用find命令查找/etc/sudoers.d/目录下的文件，并执行grep匹配日志文件配置
  grep -Ei '^\s*Defaults\s+([^#;]+,\s*)?logfile\s*=\s*(")?[^#;]+(")?' /etc/sudoers.d/* 2> /dev/null
  local result_sudoers_d=$?

  # 如果/etc/sudoers和/etc/sudoers.d/中有一个地方配置了日志文件，就认为是合规的
  if [ $result_sudoers -eq 0 ] || [ $result_sudoers_d -eq 0 ]; then
    return 0  # 合规
  else
    return 1  # 不合规
  fi
}

test_ssh_keys_permissions(){
  local keys=$1
  for keys in $(find /etc/ssh -xdev -type f -name "$keys" -exec ls {} \;);do
      if [[ "$keys" =~ "pub" ]];then
        test_permissions_0644_root_root $keys
      else
        test_permissions_0600_root_root $keys
      fi  
  done
}

test_ssh_loglevel(){
  grep -i 'loglevel' /etc/ssh/sshd_config | grep -Eqvi '(VERBOSE|INFO)' || return 0
}

test_pam_pwquality() {
  #长度大于14
  [[ $(egrep "^minlen[[:space:]]+=[[:space:]]" ${PWQUAL_CNF} | awk '{print $NF}') -ge 14 ]] || return
  #复杂度数字大小写、其他
  [[ $(grep -E '^\s*[duol]credit\s*' ${PWQUAL_CNF}) ]] || return
  #3次失败
  [[ $(grep -E '^\s*password\s+(requisite|required)\s+pam_pwquality\.so\s+(\S+\s+)*retry=[1-3]\s*(\s+\S+\s*)*(\s+#.*)?$' ${PASS_AUTH}) ]] || return
}

# 函数：检查密码锁定是否配置合规
# 返回值：0 表示合规，1 表示不合规
test_password_lockout_configured() {
  [[ $(grep "pam_tally2" ${PASS_AUTH}) ]] || return
  [[ $(grep -E "pam_(tally2|deny)\.so" ${PASS_AUTH}) ]] || return
}  

test_password_date(){
  for usr in $(cut -d: -f1 /etc/shadow); do [[ $(chage --list $usr | grep '^Last password change' | cut -d: -f2) > $(date) ]] && return 1; done
}


test_password_history() {
  test_apt_installed libpam-pwquality || return 2
  [[ $(grep -E '^\s*password\s+required\s+pam_pwhistory\.so\s+([^#]+\s+)?remember=([5-9]|[1-9][0-9]+)\b' ${PASS_AUTH}) ]] || return
}

test_password_algorithm() {
  [[ $(grep -E '^\s*password\s+(\[success=1\s+default=ignore\]|required)\s+pam_unix\.so\s+([^#]+\s+)?sha512\b' ${PASS_AUTH}) ]] || return
}

test_password_expiration() {
  egrep -q "^PASS_MAX_DAYS" ${LOGIN_DEFS} || return
  local actual_value
  actual_value=$(egrep "^PASS_MAX_DAYS" ${LOGIN_DEFS} | awk '{print $2}')
  [[ ${actual_value} -le 365 ]] ||  return
}

test_password_minium_change() {
  egrep -q "^PASS_MIN_DAYS" ${LOGIN_DEFS} || return
  local actual_value
  actual_value=$(egrep "^PASS_MIN_DAYS" ${LOGIN_DEFS} | awk '{print $2}')
  [[ ${actual_value} -gt 1 ]] || return
}

test_password_expiration_warn() {
  egrep -q "^PASS_WARN_AGE" ${LOGIN_DEFS} || return
  local actual_value
  actual_value=$(egrep "^PASS_WARN_AGE" ${LOGIN_DEFS} | awk '{print $2}')
  [[ ${actual_value} -ge 7 ]] ||  return
}

test_password_lock() {
  [[ $(useradd -D | grep INACTIVE | awk -F'=' '{print $2}') -le 30 ]] && [[ $(useradd -D | grep INACTIVE | awk -F'=' '{print $2}') -ne -1 ]] || return
}

# 检查系统账户是否安全的函数
test_system_accounts_configured() {
  local uid_min=$(awk '/^\s*UID_MIN/{print $2}' $LOGIN_DEFS)
  local nologin_path=$(which nologin)

  awk -F: '($1!="root" && $1!="sync" && $1!="shutdown" && $1!="halt" && $1!~/^\+/ && $3<'"$uid_min"' && $7!="'"$nologin_path"'" && $7!="/bin/false") {print}' $PASSWD
}

# 检查密码状态是否合规的函数
test_password_status_configured() {
  local uid_min=$(awk '/^\s*UID_MIN/{print $2}' $LOGIN_DEFS)
  
  awk -F: '($1!="root" && $1!~/^\+/ && $3<'"$uid_min"') {print $1}' $PASSWD |   xargs -I '{}' passwd -S '{}' | awk '($2!="L" && $2!="LK") {print $1}'
}


test_root_group_id() {
  [[ $(grep "^root:" /etc/passwd | cut -f4 -d:) -eq 0 ]] || return
}

# 检查默认用户umask是否配置合规的函数
test_default_user_umask_configured() {
  passing=""

  grep -Eiq '^\s*UMASK\s+(0[0-7][2-7]7|[0-7][2-7]7)\b' $LOGIN_DEFS &&
  grep -Eqi '^\s*USERGROUPS_ENAB\s*"?no"?\b' $LOGIN_DEFS &&
  grep -Eq '^\s*session\s+(optional|requisite|required)\s+pam_umask\.so\b' /etc/pam.d/common-session && passing=true

  grep -REiq '^\s*UMASK\s+\s*(0[0-7][2-7]7|[0-7][2-7]7|u=(r?|w?|x?)(r?|w?|x?)(r?|w?|x?),g=(r?x?|x?r?),o=)\b' /etc/profile* /etc/bash.bashrc* && passing=true

  if [ "$passing" = true ]; then
    return 0 # 合规，返回0
  else
    return 1 # 不合规，返回1
  fi
}

# 检查默认用户shell超时是否配置合规的函数
test_default_shell_timeout_configured() {
  local output1="" output2=""
  local BRC="/etc/bash.bashrc*"

  for f in $BRC /etc/profile /etc/profile.d/*.sh; do
    grep -Pq '^\s*([^#]+\s+)?TMOUT=(900|[1-8][0-9][0-9]|[1-9][0-9]|[1-9])\b' "$f" &&
    grep -Pq '^\s*([^#]+;\s*)?readonly\s+TMOUT(\s+|\s*;|\s*$|=(900|[1-8][0-9][0-9]|[1-9][0-9]|[1-9]))\b' "$f" &&
    grep -Pq '^\s*([^#]+;\s*)?export\s+TMOUT(\s+|\s*;|\s*$|=(900|[1-8][0-9][0-9]|[1-9][0-9]|[1-9]))\b' "$f" &&
    output1="$f"
  done

  grep -Pq '^\s*([^#]+\s+)?TMOUT=(9[0-9][1-9]|9[1-9][0-9]|0+|[1-9]\d{3,})\b' /etc/profile /etc/profile.d/*.sh $BRC &&
  output2=$(grep -Ps '^\s*([^#]+\s+)?TMOUT=(9[0-9][1-9]|9[1-9][0-9]|0+|[1-9]\d{3,})\b' /etc/profile /etc/profile.d/*.sh $BRC)

  if [ -n "$output1" ] && [ -z "$output2" ]; then
    return 0 # 合规，返回0
  else
    return 1 # 不合规，返回1
  fi
}

test_legacy_entries() {
  local file="${1}"
  [[ $(egrep -o '^\+:' $file)X == 'X' ]] || return
}

test_param() {
  local file="${1}" 
  local parameter="${2}" 
  local value="${3}" 
  cut -d\# -f1 ${file} | egrep -q "^${parameter}[[:space:]]+${value}"  || return
}

test_ssh_param_le() {
  local parameter="${1}" 
  local allowed_max="${2}"
  local actual_value
  actual_value=$(cut -d\# -f1 ${SSHD_CFG} | grep "${parameter}" | cut -d" " -f2)
  [[ ${actual_value} -le ${allowed_max} ]] || return 
}

test_ssh_strong_rule(){
 local rule=$1
 [[ -z $(grep -Ei "$rule" ${SSHD_CFG}) ]] || return
}


test_ssh_idle_timeout() {
  test_ssh_param_le ClientAliveInterval 300 || return
  test_ssh_param_le ClientAliveCountMax 3 || return
}

test_ssh_access() {
  local allow_users
  local allow_groups
  local deny_users
  local deny_users
  allow_users="$(cut -d\# -f1 ${SSHD_CFG} | grep "AllowUsers" | cut -d" " -f2)"
  allow_groups="$(cut -d\# -f1 ${SSHD_CFG} | grep "AllowGroups" | cut -d" " -f2)"
  deny_users="$(cut -d\# -f1 ${SSHD_CFG} | grep "DenyUsers" | cut -d" " -f2)"
  deny_groups="$(cut -d\# -f1 ${SSHD_CFG} | grep "DenyGroups" | cut -d" " -f2)"
  [[ -n "${allow_users}" ]] || return
  [[ -n "${allow_groups}" ]] || return
  [[ -n "${deny_users}" ]] || return
  [[ -n "${deny_groups}" ]] || return
}


test_access_to_su_command_restricted() {
    # 检查/etc/pam.d/su中是否存在pam_wheel.so的配置
    grep -Pi '^\h*auth\h+(?:required|requisite)\h+pam_wheel\.so\h+(?:[^#\n\r]+\h+)?((?!\2)(use_uid\b|group=\H+\b))\h+(?:[^#\n\r]+\h+)?((?!\1)(use_uid\b|group=\H+\b))(\h+.*)?$' /etc/pam.d/su > /dev/null
    local pam_wheel_configured=$?
    
    # 检查/etc/group中是否存在sugroup组
    grep sugroup /etc/group > /dev/null
    local sugroup_exists=$?

    # 判断是否限制了对au命令的访问
    if [ $pam_wheel_configured -eq 0 ] && [ $sugroup_exists -eq 0 ]; then
        # 访问au命令被限制
        return 0
    else
        # 访问au命令未被限制
        return 1
    fi
}


test_passwd_use_shadowed(){
 [[ -z $(awk -F: '($2 != "x") { print $1}' $PASSWD ) ]] || return
}

test_shadow_empty() {
  [[ -z $(awk -F: '($2 == "") { print $1 }' $SHADOW) ]] || return
}

test_group_empty() {
  [[ -z $(awk -F: '($1=="shadow") {print $NF}' $GROUP ) ]] && [[ -z $(awk -F: -v GID="$(awk -F: '($1=="shadow") {print $3}' $GROUP)" '($4==GID) {print $1}' $PASSWD) ]] || return
}

test_group_in_passwd() {
  for i in $(cut -s -d: -f4 $PASSWD | sort -u ); do
    grep -q -P "^.*?:[^:]*:$i:" $GROUP
    if [ $? -ne 0 ]; then
	return 
    fi
done
}



test_no_duplicate_names(){
  local section=$1
  local file=$2
  cut -d: -f${section} $file | sort | uniq -d | while read -r x; do 
	return 1
    done
}



test_not_duplicate_uid(){
  cut -f3 -d":" /etc/passwd | sort -n | uniq -c | while read -r count uid; do
    if [ "$count" -gt 1 ]; then
        users=$(awk -F: '($3 == n) { print $1 }' n="$uid" /etc/passwd | xargs)
	return 1
    fi
done
}


test_uid_0(){
  [[ $(awk -F: '($3 == 0) { print $1 }' $PASSWD) == "root" ]] || return
}


test_root_path_integrity() {
  RPCV="$(sudo -Hiu root env | grep '^PATH' | cut -d= -f2)"

  if echo "$RPCV" | grep -q "::"; then
    return 1
  fi

  if echo "$RPCV" | grep -q ":$"; then
    return 1
  fi
  #ls -ldH /apps/git/bin/ |awk '$9 == "." {print "PATH contains current working directory (.)"} $3 != "root" {print $9, "is not owned by root"} substr($1,6,1) != "-" {print $9, "is group writable"} substr($1,9,1) != "-" {print $9, "is world writable"}'
  IFS=":"
  for x in $RPCV; do
    unset IFS
    if [ -d "$x" ]; then
      if [ "$(ls -ldH "$x" | awk '$9 == "."')" ]; then
        return 1
      fi

      if [ "$(ls -ldH "$x" | awk '$3 != "root"')" ]; then
        return 1
      fi

      if [ "$(ls -ldH "$x" | awk 'substr($1, 6, 1) != "-"')" ]; then
        return 1
      fi

      if [ "$(ls -ldH "$x" | awk 'substr($1, 9, 1) != "-"')" ]; then
        return 1
      fi
    else
      return 1
    fi
  done

  return 0
}

test_users_home() {
  local check_type="$1"
  awk -F: '($1!~/(root|halt|sync|shutdown|nfsnobody)/ && $7!~/^(\/usr)?\/sbin\/nologin(\/)?$/ && $7!~/(\/usr)?\/bin\/false(\/)?$/) { print $1 " " $6 }' $PASSWD | while read -r user dir; do
      if [ ! -d "$dir" ]; then
          return 1
      else
          case "$check_type" in
              "own")
                  owner=$(stat -L -c "%U" "$dir")
                  if [ "$owner" != "$user" ]; then
                      return 1
                  fi
                  ;;
              "permissions")
                  dirperm=$(stat -L -c "%A" "$dir")
                  if [ "$(echo "$dirperm" | cut -c6)" != "-" ] || \
                     [ "$(echo "$dirperm" | cut -c8)" != "-" ] || \
                     [ "$(echo "$dirperm" | cut -c9)" != "-" ] || \
                     [ "$(echo "$dirperm" | cut -c10)" != "-" ]; then
                      return 1
                  fi
                  ;;
              "dot")
                  for file in "$dir"/.*; do
                      if [ ! -h "$file" ] && [ -f "$file" ]; then
                          fileperm=$(stat -L -c "%A" "$file")
                          if [ "$(echo "$fileperm" | cut -c6)" != "-" ] || \
                             [ "$(echo "$fileperm" | cut -c9)" != "-" ]; then
                              return 1
                          fi
                      fi
                  done
                  ;;
              "forward")
                  file="$dir/.forward"
                  if [ ! -h "$file" ] && [ -f "$file" ]; then
                      return 1
                  fi
                  ;;
              "netrc")
		  file="$dir/.netrc"
        	  if [ ! -h "$file" ] && [ -f "$file" ]; then
        	      if stat -L -c "%A" "$file" | cut -c4-10 | grep -Eq '[^-]+'; then
			return 1
        	      fi
        	  fi
		  ;;
              "rhosts")
		  file="$dir/.rhosts"
       		   if [ ! -h "$file" ] && [ -f "$file" ]; then
			return 1
       		   fi
                  ;;
          esac
      fi
  done 
}
